package com.mihuspring.www.context;


import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassUtils {
  public static void main(String[] args){
    try {
      Set<Class<?>> classSet = getClassSet("com.mihuspring.www");
      for(Class c : classSet){
        System.out.println(c);
      }
    }catch (Throwable err){
      System.out.println(err);
    }
  }
  public static ClassLoader getClassLoader(){
    return Thread.currentThread().getContextClassLoader();
  }
  public static Class<?> loadClass(String className){
    try{
      return getClassLoader().loadClass(className);
    }catch (ClassNotFoundException err){
      throw new RuntimeException(err);
    }
  }
  public static Set<Class<?>> getClassSet (String packageName) throws IOException{
    Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
    Set<Class<?>> classSet = new HashSet<>();
    while (urls.hasMoreElements()){
      URL url = urls.nextElement();
      if (url != null) {
        String protocol = url.getProtocol();
        if(protocol.equals("file")){
          String packagePath = url.getPath().replace(" ", "");
          addClass(packageName, packagePath, classSet);
        }else if(protocol.equals("jar")){
          JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
          if(jarURLConnection != null){
            JarFile jarFile = jarURLConnection.getJarFile();
            if(jarFile != null){
              Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
              while (jarEntryEnumeration.hasMoreElements()){
                JarEntry jarEntry = jarEntryEnumeration.nextElement();
                String jarEntryName = jarEntry.getName();
                if(jarEntryName.endsWith(".class")){
                  String className = jarEntryName.substring(0, jarEntryName.lastIndexOf('.'));
                  className = className.replace("/", ".");
                  doAddClass(className, classSet);
                }
              }
            }
          }
        }
      }
    }
    return classSet;
  }
  public static void doAddClass(String className, Set<Class<?>> classSet){
    Class<?> newClass = loadClass(className);
    classSet.add(newClass);
  }
  public static void addClass(String packageName, String packagePath, Set<Class<?>> classSet){
    File[] files = new File(packagePath).listFiles(new FileFilter() {
      @Override
      public boolean accept(File pathname) {
        return (pathname.isFile() && pathname.getName().endsWith(".class")) || pathname.isDirectory();
      }
    });
    for(File file : files){
      String fileName = file.getName();
      if(file.isFile()){
        String className = fileName.substring(0, fileName.lastIndexOf('.'));
        if(StringUtils.isNotEmpty(packageName)){
          className = packageName + "." + className;
        }
        doAddClass(className, classSet);
      }else {
        String nextPackageName = fileName;
        String nextPackagePath = fileName;
        if(StringUtils.isNotEmpty(packageName)){
          nextPackageName = packageName + "." + fileName;
        }
        if(StringUtils.isNotEmpty(packagePath)){
          nextPackagePath = packagePath + "/" + fileName;
        }
        addClass(nextPackageName, nextPackagePath, classSet);
      }
    }
  }
}
